package com.yupi.project.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * Redis配置类
 *
 * @author yupi
 */
@Configuration
public class RedisConfig {

    /**
     * 令牌桶Lua脚本
     * 实现原子性的令牌桶算法，确保在分布式环境下的一致性
     * KEYS[1]: 令牌桶的key
     * ARGV[1]: 最大令牌数
     * ARGV[2]: 令牌生成速率（每秒）
     * ARGV[3]: 当前时间戳（毫秒）
     * ARGV[4]: 请求令牌数量（默认为1）
     * 
     * 返回值：
     * 1: 获取令牌成功
     * 0: 获取令牌失败（令牌不足）
     */
    @Bean
    public DefaultRedisScript<Long> rateLimiterScript() {
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        redisScript.setLocation(new ClassPathResource("scripts/rate_limiter.lua"));
        redisScript.setResultType(Long.class);
        return redisScript;
    }
    
    /**
     * 基于CAS的令牌桶Lua脚本
     * 实现原子性的令牌桶算法，支持CAS操作，确保在分布式环境下的一致性
     * KEYS[1]: 令牌桶的key
     * ARGV[1]: 最大令牌数
     * ARGV[2]: 令牌生成速率（每秒）
     * ARGV[3]: 当前时间戳（毫秒）
     * ARGV[4]: 请求令牌数量（默认为1）
     * ARGV[5]: 版本号（用于CAS操作，可选）
     * 
     * 返回值：
     * List格式: [状态码, 当前令牌数, 下一个令牌预计可用时间, 当前版本号]
     * 状态码: 1表示获取令牌成功，0表示获取令牌失败
     */
    @Bean
    public DefaultRedisScript<List> rateLimiterCasScript() {
        DefaultRedisScript<List> redisScript = new DefaultRedisScript<>();
        redisScript.setLocation(new ClassPathResource("scripts/rate_limiter_cas.lua"));
        redisScript.setResultType(List.class);
        return redisScript;
    }

    /**
     * 配置RedisTemplate
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(connectionFactory);
        
        // 使用StringRedisSerializer来序列化和反序列化redis的key值
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(stringRedisSerializer);
        
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}